/*
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */
package com.l2jserver.gameserver.custom;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.actor.instance.L2HonorPointsManagerInstance.SaveHonor;
import com.l2jserver.gameserver.skills.Env;
import com.l2jserver.gameserver.skills.Stats;
import com.l2jserver.gameserver.skills.funcs.Func;

/**
 * @author Home
 *
 */
public class PcHonor
{
	private static final Logger _log = Logger.getLogger(PcHonor.class.getName());
	private final HashMap<Stats, Integer> _bonus = new HashMap<Stats, Integer>();
	private HonorRankModel _rank = null;
	private final Integer _ownerId;
	private int _statPoints = 0;
	private int _honorPoints = 0;
	private final L2PcInstance[] _owner = new L2PcInstance[1];
	
	public PcHonor(int ownerId, HonorRankModel rank)
	{
		_ownerId = ownerId;
		setRank(rank);
	}
	
	public void setStatPoints(int points)
	{
		_statPoints = points;
	}
	
	public void setOwner(L2PcInstance player)
	{
		if (_owner[0] == null)
		{
			if (_ownerId != player.getObjectId())
			{
				_log.warning("Player " + player.getName() + " tried to pick up another user's honors template. Real Owner ObjectId = " + _ownerId + ", " + player.getName() + " ObjectId = " + player.getObjectId());
				return;
			}
			_owner[0] = player;
			updateStatCalcs();
			updateTitleColor();
		}
		else
			_log.warning("Attenpted to change the owner of an already owned honors template.");
	}
	
	/**
	 * 
	 */
	public void updateTitleColor()
	{
		if (getRank() != null)
		{
			int color = _owner[0].getFaction().getFactionId() == 1 ? getRank().getTitleColor1() : getRank().getTitleColor2();
			if (color != 0x0)
				_owner[0].getAppearance().setTitleColor(color);
		}
		
	}
	
	public void setHonorPoints(int points)
	{
		_honorPoints = points;
	}
	
	public void addHonorPoints(int value)
	{
		setHonorPoints(getHonorPoints() + value);
	}
	
	public void saveHonorToDB()
	{
		ThreadPoolManager.getInstance().scheduleGeneral(new SaveHonor(this), (long) 1E3);
	}
	
	public void setRankAndAddPoints(HonorRankModel rank)
	{
		setRank(rank);
		setStatPoints(_statPoints + getRank().getSpendablePoints());
	}
	
	public void setRank(HonorRankModel rank)
	{
		_rank = rank.clone();
	}
	
	public void addStat(Stats stat, int value)
	{
		synchronized (_bonus)
		{
			if (_bonus.containsKey(stat))
			{
				int oldVl = _bonus.get(stat);
				_bonus.put(stat, oldVl + value);
				return;
			}
			else
			{
				_bonus.put(stat, value);
				return;
			}
		}
	}
	
	public void addStatAndSave(Stats stat, int value)
	{
		synchronized (_bonus)
		{
			if (_bonus.containsKey(stat))
			{
				int oldVl = _bonus.get(stat);
				_bonus.put(stat, oldVl + value);
				ThreadPoolManager.getInstance().scheduleGeneral(new SaveStat(stat.getValue(), oldVl + value, getOwnerId()), (long) 1E3);
				return;
			}
			else
			{
				_bonus.put(stat, value);
				ThreadPoolManager.getInstance().scheduleGeneral(new InsertStat(stat.getValue(), value, getOwnerId()), (long) 1E3);
				return;
			}
		}
		
	}
	
	public void updateStatCalcs()
	{
		_owner[0].removeStatsOwner(_ownerId);
		for (Stats stat : _bonus.keySet())
			_owner[0].addStatFunc(new StatBonus(stat));
	}
	
	public int getOwnerId()
	{
		return _ownerId;
	}
	
	public int getBonus(Stats stat)
	{
		synchronized (_bonus)
		{
			if (_bonus.containsKey(stat))
				return _bonus.get(stat);
			else
				return 0;
		}
	}
	
	public HonorRankModel getRank()
	{
		return _rank;
	}
	
	public int getHonorPoints()
	{
		return _honorPoints;
	}
	
	public int getStatPoints()
	{
		return _statPoints;
	}
	
	public boolean hasOwner()
	{
		return _owner[0] != null;
	}
	
	private class StatBonus extends Func
	{
		private final Stats _stat;
		
		protected StatBonus(Stats stat)
		{
			super(stat, 0x10, _ownerId);
			_stat = stat;
		}
		
		/* (non-Javadoc)
		 * @see com.l2jserver.gameserver.skills.funcs.Func#calc(com.l2jserver.gameserver.skills.Env)
		 */
		@Override
		public void calc(Env env)
		{
			env.value += getBonus(_stat);
		}
	}
	
	private static class SaveStat implements Runnable
	{
		private final String _name;
		private final int _value;
		private final int _ownerId;
		
		SaveStat(String statName, int value, int ownerId)
		{
			_name = statName;
			_value = value;
			_ownerId = ownerId;
		}
		
		/* (non-Javadoc)
		 * @see java.lang.Runnable#run()
		 */
		@Override
		public void run()
		{
			Connection con = null;
			try
			{
				con = L2DatabaseFactory.getInstance().getConnection();
				PreparedStatement statement = con.prepareStatement("UPDATE honor_stats SET bonus = ? WHERE objectId = ? AND statName = ?");
				statement.setInt(1, _value);
				statement.setInt(2, _ownerId);
				statement.setString(3, _name);
				statement.executeUpdate();
			}
			catch (Exception e)
			{
				_log.log(Level.SEVERE, null, e);
			}
			finally
			{
				try
				{
					con.close();
				}
				catch (Exception e)
				{
				}
			}
		}
		
	}
	
	private static class InsertStat implements Runnable
	{
		private final String _name;
		private final int _value;
		private final int _ownerId;
		
		InsertStat(String statName, int value, int ownerId)
		{
			_name = statName;
			_value = value;
			_ownerId = ownerId;
		}
		
		/* (non-Javadoc)
		 * @see java.lang.Runnable#run()
		 */
		@Override
		public void run()
		{
			Connection con = null;
			try
			{
				con = L2DatabaseFactory.getInstance().getConnection();
				PreparedStatement statement = con.prepareStatement("INSERT INTO honor_stats(objectId,statName,bonus) VALUES (?,?,?)");
				statement.setInt(1, _ownerId);
				statement.setString(2, _name);
				statement.setInt(3, _value);
				statement.executeUpdate();
			}
			catch (Exception e)
			{
				_log.log(Level.SEVERE, null, e);
			}
			finally
			{
				try
				{
					con.close();
				}
				catch (Exception e)
				{
				}
			}
		}
		
	}
	
}
